﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using GrayParrot.Core;
using GrayParrot.Extensions.Enumeration;
using GrayParrot.Extensions.Strings;

namespace GrayParrot.Web.Controls
{
    [DefaultProperty("Text")]
    [ToolboxData("<{0}:JQDataTable runat=server></{0}:JQDataTable>")]
    public class JQDataTable : WebControl
    {
        private EventsConfig m_eventsConfig = new EventsConfig();
        private ColumnsConfig m_columnsConfig = new ColumnsConfig();
        private ControllerConfig m_controllerConfig = new ControllerConfig();
        private FeaturesConfig m_featuresConfig = new FeaturesConfig();
        private string m_bootstrapClasses = string.Empty;
        private bool m_individualSearch = false;

        [Bindable(true)]
        [Category("JQDataTables")]
        [DefaultValue(null)]
        [Localizable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty)]
        public string BootstrapClasses
        {
            get { return m_bootstrapClasses; }
            set { m_bootstrapClasses = value; }
        }

        [Bindable(true)]
        [Category("JQDataTables")]
        [DefaultValue(null)]
        [Localizable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty)]
        public bool RenderScripts
        {
            get;
            set;
        }

        [Bindable(true)]
        [Category("JQDataTables")]
        [DefaultValue(null)]
        [Localizable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty)]
        public FeaturesConfig FeaturesConfig
        {
            get { return m_featuresConfig; }
            set { m_featuresConfig = value; }
        }

        /// <summary>
        /// Gets or sets the columns config.
        /// </summary>
        /// <value>
        /// The columns config.
        /// </value>
        [Bindable(true)]
        [Category("JQDataTables")]
        [DefaultValue(null)]
        [Localizable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty)]
        public ColumnsConfig ColumnsConfig
        {
            get { return m_columnsConfig; }
            set { m_columnsConfig = value; }
        }

        /// <summary>
        /// Gets or sets the events configuration.
        /// </summary>
        /// <value>
        /// The events configuration.
        /// </value>
        [Bindable(true)]
        [Category("JQDataTables")]
        [DefaultValue(null)]
        [Localizable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty)]
        public EventsConfig EventsConfig
        {
            get { return m_eventsConfig; }
            set { m_eventsConfig = value; }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty)]
        public Buttons Buttons { get; set; }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty)]
        public Toolbar Toolbar { get; set; }

        [Bindable(true)]
        [Category("Appearance")]
        [DefaultValue(null)]
        [Localizable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty)]
        public ControllerConfig ControllerConfig
        {
            get { return m_controllerConfig; }
            set { m_controllerConfig = value; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the table is responsive.
        /// </summary>
        /// <value>
        /// <c>true</c> if this table is responsive; otherwise, <c>false</c>.
        /// </value>
        [Bindable(true)]
        [Category("JQDataTables")]
        [DefaultValue(false)]
        [Localizable(true)]
        public bool IsResponsive { get; set; }

        /// <summary>
        /// Gets or sets the selection mode.
        /// </summary>
        /// <value>
        /// The select mode.
        /// </value>
        [Bindable(true)]
        [Category("JQDataTables")]
        [DefaultValue(false)]
        [Localizable(true)]
        public SelectionModes SelectionMode { get; set; }

        /// <summary>
        /// Renders the contents.
        /// </summary>
        /// <param name="output">The output.</param>
        protected override void RenderContents(HtmlTextWriter output)
        {
            if (this.Height.IsEmpty)
            {
                this.Height = new Unit(100.0, UnitType.Percentage);
            }

            if (this.Width.IsEmpty)
            {
                this.Width = new Unit(100, UnitType.Percentage);
            }

            output.WriteLine();

            //string m_externalFilterDiv = DefineExternalFilters();
            //output.Write(m_externalFilterDiv);
            //output.RenderBeginTag(HtmlTextWriterTag.Br);
            //output.RenderEndTag();

            /* if selection mode 'Multi' is choose, the prepare the div for the selected items dialog */
            output.AddAttribute("id", "selectedItemsDialog");
            output.AddAttribute("title", "Elementi Selezionati");
            output.AddAttribute("style", "display:none");
            output.RenderBeginTag(HtmlTextWriterTag.Div);
            output.AddAttribute("id", "selItemsTable");
            output.RenderBeginTag(HtmlTextWriterTag.Div);
            output.RenderEndTag();
            output.RenderEndTag();
            /* if selection mode 'Multi' is choose, the prepare the div for the selected items dialog */

            output.AddAttribute("style", string.Format("height:{0}{1};width:{2}{3}", this.Height.Value, this.Height.TypeSymbol(), this.Width.Value, this.Width.TypeSymbol()));  // CONTAINER
            output.AddAttribute("id", string.Format("table{0}Container", this.ID));  // CONTAINER
            output.RenderBeginTag(HtmlTextWriterTag.Div);

            output.WriteLine();

            output.AddAttribute("id", "table" + this.ID);  // TABLE
            //output.AddAttribute("width", "100%");
            output.AddAttribute("class", m_bootstrapClasses);  // TABLE
            output.RenderBeginTag(HtmlTextWriterTag.Table);

            output.RenderBeginTag(HtmlTextWriterTag.Thead); // THead
            output.RenderBeginTag(HtmlTextWriterTag.Tr);    // THead Tr

            //
            if ((this.ColumnsConfig != null) && (this.ColumnsConfig.Columns != null))
            {
                if (this.SelectionMode == SelectionModes.Multi)
                {
                    output.RenderBeginTag(HtmlTextWriterTag.Th);    // needed for the checkbox multi selection mode...
                    output.Write("<input name=\"select_all\" value=\"1\" type=\"checkbox\" />");
                    output.RenderEndTag();
                }

                foreach (Column c in this.ColumnsConfig.Columns)
                {
                    if (c.Type == ColumnTypes.Action)
                    {
                        output.RenderBeginTag(HtmlTextWriterTag.Th);    // a th element for each property of the object...
                        output.Write((string.IsNullOrWhiteSpace(c.Header) ? "Actions" : c.Header.SplitCamelCase().Trim()));
                        output.RenderEndTag();
                    }
                    else
                    {
                        string t = c.Header.SplitCamelCase().Trim();
                        int pos = t.NthOccurenceOf(' ', 2);
                        t = t.ReplaceCharAt(pos, "<br/>");

                        output.RenderBeginTag(HtmlTextWriterTag.Th);    // a th element for each property of the object...
                        output.Write(c.Header.Trim());
                        output.RenderEndTag();
                    }
                }
            }

            output.RenderEndTag();                          // THead Tr
            output.RenderEndTag();                          // THead

            output.WriteLine();
            output.RenderBeginTag(HtmlTextWriterTag.Tbody);  // Tbody
            output.RenderEndTag();
            output.WriteLine();

            //if (EnableIndividualSearch)
            //{
            //    output.RenderBeginTag(HtmlTextWriterTag.Tfoot); // Tfoot
            //    output.RenderBeginTag(HtmlTextWriterTag.Tr);    // Tfoot Tr

            //    if ((this.ColumnsConfig != null) && (this.ColumnsConfig.Columns != null))
            //    {
            //        foreach (Column c in this.ColumnsConfig.Columns)
            //        {
            //            output.RenderBeginTag(HtmlTextWriterTag.Th);    // a th element for each property of the object...
            //            output.Write(c.Header.Trim());
            //            output.RenderEndTag();
            //        }
            //    }

            //    output.RenderEndTag();                          // Tfoot Tr
            //    output.RenderEndTag();   // TFoot
            //}

            output.RenderEndTag();   // TABLE

            output.WriteLine();

            output.RenderEndTag();   // CONTAINER

            output.WriteLine();

            if (RenderScripts)
            {
                string baseTableScript = AddTableBaseScript();

                output.RenderBeginTag(HtmlTextWriterTag.Script);
                output.Write(baseTableScript);
                output.RenderEndTag();
            }
        }

        public string RenderExternalFilters()
        {
            string retValue = string.Empty;

            Searching m_searchingFeature = (Searching)FeaturesConfig.Features.SingleOrDefault(x => x.GetType() == typeof(Searching));

            if (m_searchingFeature.Value == SearchTypes.QueryBuilder)
            {
                retValue = DefineQueryBuilderFilters();
            }
            else
            {
                retValue = DefineExternalFilters();
            }

            return retValue;
        }

        public string RenderScriptsManually(bool renderOnDocumentReady = true, bool addScriptTags = true)
        {
            string retValue = string.Empty;

            StringBuilder sb = new StringBuilder();

            if(addScriptTags)
              sb.AppendLine("<script>");

            sb.AppendLine(AddTableBaseScript(renderOnDocumentReady));
            
            if (addScriptTags)
              sb.AppendLine("</script>");

            retValue = sb.ToString();

            return retValue;
        }

        private string AddTableBaseScript(bool renderOnDocumentReady = true)
        {
            string retValue = string.Empty;

            string m_options = DefineDataTablesOptions();

            string m_ajaxBlock = DefineAjaxBlock();

            string m_columns = DefineDataTablesColumns();

            string m_filters = DefineDataTablesSearches();

            string[] m_selectionMode = DefineDataTablesSelectionMode();

            string m_buttonsDefinition = DefineDataTablesButtons();

            string m_sequenceTableParts = DefineTablePartsSequence();

            string m_callbacksDefinition = DefineTableCallbacks();

            string m_eventsDefinition = DefineTableEvents();

            string m_editable = DefineEditableColumns();

            //string m_externalSearch = DefineExternalFilters();

            string m_actionHandlers = DefineActionButtonHandlers();

            string m_toolbar = DefineDataTablesToolbar();

            string m_queryBuilderCfg = DefineQueryBuilderConfiguration();

            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("{0}", m_options);
            sb.AppendFormat("{0},", m_ajaxBlock);
            sb.AppendFormat("{0},", m_columns);
            sb.AppendFormat("{0},", m_filters);

            var assembly = Assembly.GetExecutingAssembly();
            var resourceName = "GrayParrot.Web.Controls.Datatables.GridTemplate.txt";

            if (!renderOnDocumentReady)
            {
                resourceName = "GrayParrot.Web.Controls.Datatables.GridTemplate2.txt";
            }

            using (Stream stream = assembly.GetManifestResourceStream(resourceName))
            using (StreamReader reader = new StreamReader(stream))
            {
                retValue = reader.ReadToEnd();

                //retValue = string.Format(retValue, this.ID, sb.ToString());

                retValue = string.Format(retValue, this.ID,
                                                   m_options,
                                                   m_ajaxBlock,
                                                   m_columns,
                                                   m_selectionMode[0],
                                                   m_buttonsDefinition,
                                                   m_callbacksDefinition,
                                                   m_sequenceTableParts,
                                                   m_filters,
                                                   m_selectionMode[1],
                                                   m_eventsDefinition,
                                                   m_editable,
                                                   m_actionHandlers,
                                                   m_toolbar,
                                                   m_queryBuilderCfg);
            }

            return retValue;
        }

        private string DefineActionButtonHandlers()
        {
            string retValue = string.Empty;

            StringBuilder sb = new StringBuilder();

            foreach (Column c in this.ColumnsConfig.Columns)
            {
                if (c.Type == ColumnTypes.Action)
                {
                    foreach (ActionDetail ac in ((ActionColumn)c).Actions)
                    {
                        sb.AppendFormat("$('#table{0} tbody').on('click', '.{1}', function () {{\n", this.ID, (!string.IsNullOrWhiteSpace(ac.Class) ? ac.Class : ac.Callback));
                        sb.AppendFormat("  var data = m_table{0}.row($(this).parents('tr')).data();\n", this.ID);
                        sb.AppendFormat("  {0}(data);\n", ac.Callback);
                        sb.AppendLine("});");
                    }
                }
            }

            retValue = sb.ToString();

            return retValue;
        }

        private string DefineQueryBuilderFilters()
        {
            string retValue = string.Empty;

            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("<!-- QueryBuilder Filter Container for m_table{0} -->\n", this.ID);
            sb.AppendFormat("<div id=\"builder_{0}\"></div>\n", this.ID);
            sb.AppendFormat("<input type='Button' value='Filter' id=\"btn_builder__filter_{0}\" onclick=\"RedrawGrid(m_table{0});\" />\n", this.ID);
            sb.AppendFormat("<input type='Button' value='Reset' id=\"btn_builder__reset_{0}\" onclick=\" $('#builder_{0}').queryBuilder('reset');\" />\n", this.ID);
            sb.AppendFormat("<div id=\"builder_{0}\"></div>\n", this.ID);
            sb.AppendFormat("<!-- QueryBuilder Filter Container for m_table{0} -->\n", this.ID);

            retValue = sb.ToString();

            return retValue;
        }

        private string DefineQueryBuilderConfiguration()
        {
            string retValue = string.Empty;

            Searching m_searchingFeature = (Searching)FeaturesConfig.Features.SingleOrDefault(x => x.GetType() == typeof(Searching));
            if ((m_searchingFeature != null) && (m_searchingFeature.QueryBuilderFilters != null))
            {
                if (m_searchingFeature.Value == SearchTypes.QueryBuilder)
                {
                    StringBuilder sb = new StringBuilder();
                    StringBuilder sb1 = new StringBuilder();
                    StringBuilder sb2 = new StringBuilder();
                    StringBuilder sb3 = new StringBuilder();
                    string m_datePickerCfg = string.Empty;
                    string m_validationCfg = string.Empty;
                    string m_columnType = string.Empty;

                    sb1.AppendFormat("var rules_{0} = {{condition: 'AND', rules: [\n", this.ID);   //style=\"display:none\"

                    sb2.AppendFormat("var filters_{0} = [", this.ID);

                    foreach (QueryBuilderColumnFilter c in m_searchingFeature.QueryBuilderFilters)
                    {
                        m_validationCfg = string.Empty;
                        m_datePickerCfg = string.Empty;

                        m_columnType = c.QueryBuilderDataType.ToString().ToLower();

                        /* rules definitions */
                        sb1.AppendFormat("{{ id: '{0}', operator: 'equal', value: null }},\n", c.ColumnName);

                        /* columns defitions */
                        sb2.AppendLine(c.ToString());

                        //if ((c.QueryBuilderInputType == QueryBuilderInputTypes.Checkbox) ||
                        //    (c.QueryBuilderInputType == QueryBuilderInputTypes.Radio))
                        //{
                        //    if (c.GetType() == typeof(QBCheckBoxColumnFilter))
                        //    {
                        //        string m = ((QBCheckBoxColumnFilter)c).SetupValues(this.ID);
                        //        sb3.AppendLine(m);
                        //    }
                        //}
                    }

                    sb1.AppendLine("]}; ");
                    sb2.AppendLine("];");

                    string m_sb1 = sb1.ToString();
                    m_sb1 = m_sb1.Remove(m_sb1.LastIndexOf(","), 1);
                    sb.AppendFormat("{0}\n", m_sb1);

                    string m_sb2 = sb2.ToString();
                    m_sb2 = m_sb2.Remove(m_sb2.LastIndexOf(","), 1);
                    sb.AppendFormat("{0}\n", m_sb2);

                    sb.AppendFormat("InitQueryBuilder('builder_{0}', filters_{0}, rules_{0});\n", this.ID);

                    /* Async data loading for Radio and checkboxes */
                    //sb.AppendLine(sb3.ToString());

                    retValue = sb.ToString();
                }
            }

            return retValue;
        }

        private string DefineQueryBuilderConfiguration__()
        {
            string retValue = string.Empty;

            Searching m_searchingFeature = (Searching)FeaturesConfig.Features.SingleOrDefault(x => x.GetType() == typeof(Searching));
            if (m_searchingFeature != null)
            {
                if (m_searchingFeature.Value == SearchTypes.QueryBuilder)
                {
                    StringBuilder sb = new StringBuilder();
                    StringBuilder sb1 = new StringBuilder();
                    StringBuilder sb2 = new StringBuilder();
                    string m_datePickerCfg = string.Empty;
                    string m_validationCfg = string.Empty;

                    sb1.AppendFormat("var rules_{0} = {{condition: 'AND', rules: [\n", this.ID);   //style=\"display:none\"

                    sb2.AppendFormat("var filters_{0} = [", this.ID);

                    foreach (Column c in this.ColumnsConfig.Columns)
                    {
                        ColumnFilter m_filter = m_searchingFeature.Filters.SingleOrDefault(x => x.ColumnName.Equals(c.Name, StringComparison.InvariantCultureIgnoreCase));

                        if ((m_filter != null) && (c.Visible))
                        {
                            m_validationCfg = string.Empty;
                            m_datePickerCfg = string.Empty;

                            if ((m_filter.Type == FilterTypes.Date) || (m_filter.Type == FilterTypes.DateRange))
                            {
                                m_validationCfg = string.Format("validation: {{ format: '{0}', allow_empty_value: true }}", ((DateColumnFilter)m_filter).DateFormat);
                                m_datePickerCfg = string.Format("plugin: 'datepicker', plugin_config: {{ format: '{0}', todayBtn: 'linked', todayHighlight: true, autoclose: true }},",
                                                               ((DateColumnFilter)m_filter).DateFormat);
                            }
                            else
                            {
                                m_validationCfg = "validation: { allow_empty_value: true }";
                            }

                            sb1.AppendFormat("{{ id: '{0}', operator: 'equal', value: null }},\n", c.Name);

                            sb2.AppendFormat("{{ id: '{0}', label: '{1}', type: '{2}', {3} {4} }},", 
                                                     c.Name, 
                                                     c.Name,
                                                     c.Type.ToString().ToLower(), 
                                                     m_datePickerCfg,
                                                     m_validationCfg
                                                     );
                        }
                    }

                    sb1.AppendLine("]}; ");
                    sb2.AppendLine("];");

                    string m_sb1 = sb1.ToString();
                    m_sb1 = m_sb1.Remove(m_sb1.LastIndexOf(","), 1);
                    sb.AppendFormat("{0}\n", m_sb1);

                    string m_sb2 = sb2.ToString();
                    m_sb2 = m_sb2.Remove(m_sb2.LastIndexOf(","), 1);
                    sb.AppendFormat("{0}\n", m_sb2);

                    sb.AppendFormat("InitQueryBuilder('builder_{0}', filters_{0}, rules_{0});", this.ID);

                    retValue = sb.ToString();
                }
            }

            return retValue;
        }

        private string DefineExternalFilters__()
        {
            string retValue = string.Empty;

            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("<!-- External Filter Container for m_table{0} -->\n", this.ID);

            Searching m_searchingFeature = (Searching)FeaturesConfig.Features.SingleOrDefault(x => x.GetType() == typeof(Searching));
            if ((m_searchingFeature != null) && m_searchingFeature.ExternalFilters)
            {
                //m_individualSearch = false;
                m_individualSearch = ((m_searchingFeature.Value == SearchTypes.Individual || m_searchingFeature.Value == SearchTypes.None) ? true : false);

                if ((m_searchingFeature.Value == SearchTypes.Individual) || (m_searchingFeature.Value == SearchTypes.Both))
                {
                    sb.AppendFormat("<div id=\"externaly_triggered_wrapper_{0}\" class=\"externaly_triggered_wrapper\" >\n", this.ID);   //style=\"display:none\"

                    int index = (this.SelectionMode == SelectionModes.Multi ? 1 : 0);
                    foreach (Column c in this.ColumnsConfig.Columns)
                    {
                        ColumnFilter m_filter = m_searchingFeature.Filters.SingleOrDefault(x => x.ColumnName.Equals(c.Name, StringComparison.InvariantCultureIgnoreCase));

                        if ((m_filter != null) && (c.Visible))
                        {
                            sb.AppendLine("<div>");
                            sb.AppendFormat("    <span>{0}:</span>\n", (!string.IsNullOrWhiteSpace(m_filter.DefaultLabel) ? m_filter.DefaultLabel : m_filter.ColumnName));
                            sb.AppendFormat("    <span id=\"efc_{0}_{1}\"></span>\n", this.ID, index);
                            sb.AppendLine("</div>");
                        }

                        index++;
                    }

                    sb.AppendLine("</div>");
                    sb.AppendFormat("<div id=\"externaly_triggered_wrapper-controls_{0}\">\n", this.ID);
                    sb.AppendLine(" <div>");
                    sb.AppendFormat("	 <input type=\"button\" onclick=\"yadcf.exFilterExternallyTriggered(m_table{0});\" value=\"Filter\" class=\"some_btn general_btn\">", this.ID);
                    sb.AppendFormat("	 <input type=\"button\" onclick=\"yadcf.exResetAllFilters(m_table{0});\" value=\"Reset\" class=\"some_btn general_btn\">", this.ID);
                    sb.AppendLine(" </div>");
                    sb.AppendLine("</div>");
                }
            }

            sb.AppendFormat("<!-- External Filter Container for m_table{0} -->\n", this.ID);

            retValue = sb.ToString();

            return retValue;
        }

        private string DefineExternalFilters()
        {
            string retValue = string.Empty;

            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("<!-- External Filter Container for m_table{0} -->\n", this.ID);

            Searching m_searchingFeature = (Searching)FeaturesConfig.Features.SingleOrDefault(x => x.GetType() == typeof(Searching));
            if ((m_searchingFeature != null) && m_searchingFeature.ExternalFilters)
            {
                //m_individualSearch = false;
                m_individualSearch = ((m_searchingFeature.Value == SearchTypes.Individual || m_searchingFeature.Value == SearchTypes.None) ? true : false);

                if ((m_searchingFeature.Value == SearchTypes.Individual) || (m_searchingFeature.Value == SearchTypes.Both))
                {
                    sb.AppendFormat("<div id=\"externaly_triggered_wrapper_{0}\" class=\"externaly_triggered_wrapper\" >\n", this.ID);   //style=\"display:none\"

                    int index = (this.SelectionMode == SelectionModes.Multi ? 1 : 0);
                    foreach (ColumnFilter c in m_searchingFeature.Filters)
                    {
                        sb.AppendLine("<div>");
                        sb.AppendFormat("    <span>{0}:</span>\n", (!string.IsNullOrWhiteSpace(c.DefaultLabel) ? c.DefaultLabel : c.ColumnName));
                        sb.AppendFormat("    <span id=\"efc_{0}_{1}\"></span>\n", this.ID, index);
                        sb.AppendLine("</div>");

                        index++;
                    }

                    sb.AppendLine("</div>");
                    sb.AppendFormat("<div id=\"externaly_triggered_wrapper-controls_{0}\">\n", this.ID);
                    sb.AppendLine(" <div>");
                    sb.AppendFormat("	 <input type=\"button\" onclick=\"yadcf.exFilterExternallyTriggered(m_table{0});\" value=\"Filter\" class=\"some_btn general_btn\">", this.ID);
                    sb.AppendFormat("	 <input type=\"button\" onclick=\"yadcf.exResetAllFilters(m_table{0});\" value=\"Reset\" class=\"some_btn general_btn\">", this.ID);
                    sb.AppendLine(" </div>");
                    sb.AppendLine("</div>");
                }
            }

            sb.AppendFormat("<!-- External Filter Container for m_table{0} -->\n", this.ID);

            retValue = sb.ToString();

            return retValue;
        }

        private string DefineDataTablesOptions()
        {
            string retValue = string.Empty;

            StringBuilder sb = new StringBuilder();

            string m_comma = ",";

            if (this.ControllerConfig.LoadingMode != LoadingModes.Manual)
            {
                sb.AppendLine("\"processing\": true");
                sb.AppendLine(",\"serverSide\": true");
            }

            if ((this.ControllerConfig.LoadingMode == LoadingModes.OnDemand) || (this.ControllerConfig.LoadingMode == LoadingModes.Redraw))
            {
                sb.Append(",\"deferLoading\": 0\n");
            }

            if ((this.FeaturesConfig != null) && (this.FeaturesConfig.Features != null))
            {
                for (int i = 0; i < this.FeaturesConfig.Features.Count(); i++)
                {
                    if (i == 0)
                    {
                        if (this.ControllerConfig.LoadingMode == LoadingModes.Manual)
                        {
                            m_comma = "";
                        }
                    }
                    else
                    {
                        m_comma = ",";
                    }

                    sb.AppendFormat("{0}{1}\n", m_comma, this.FeaturesConfig.Features[i].ToString());
                }
            }

            if (this.IsResponsive)
            {
                sb.AppendLine(",\"responsive\": true");
            }

            if ((this.ColumnsConfig != null) && (!string.IsNullOrWhiteSpace(this.ColumnsConfig.Key)))
            {
                sb.AppendFormat("\n,\"rowId\": '{0}'", this.ColumnsConfig.Key);
            }

            retValue = sb.ToString();

            return retValue;
        }

        private string DefineAjaxBlock()
        {
            string retValue = string.Empty;

            if ((this.ControllerConfig.LoadingMode == LoadingModes.OnLoad) ||
                (this.ControllerConfig.LoadingMode == LoadingModes.OnDemand) ||
                (this.ControllerConfig.LoadingMode == LoadingModes.Redraw))
            {
                StringBuilder sb = new StringBuilder();

                if ((this.FeaturesConfig != null) && (this.FeaturesConfig.Features != null) && (this.FeaturesConfig.Features.Count() > 0))
                {
                    sb.AppendLine(",\"ajax\": {");
                }
                else
                {
                    sb.AppendLine("\"ajax\": {");
                }

                sb.AppendLine("\"type\": \"POST\",");
                sb.AppendFormat("\"url\": \"{0}\",\n", this.ControllerConfig.Url);

                sb.AppendLine("\"data\": function(data) {");
                sb.AppendFormat("  data.SelectionMode = '{0}';\n", this.SelectionMode);

                Searching m_searchingFeature = (Searching)FeaturesConfig.Features.SingleOrDefault(x => x.GetType() == typeof(Searching));
                if ((m_searchingFeature != null) && (m_searchingFeature.Value == SearchTypes.QueryBuilder))
                {
                    sb.AppendFormat("  data.QueryBuilder = GetQueryBuilderSQL('builder_{0}');\n", this.ID);
                    //sb.AppendFormat("  var dt_params = $('#m_table{0}').data('dt_params');\n", this.ID);
                    //sb.AppendLine("  if(dt_params){ $.extend(data, dt_params); }\n");
                }

                if (this.ControllerConfig.ControllerParameters.Count() > 0)
                {
                    foreach (ControllerParameter cp in this.ControllerConfig.ControllerParameters)
                    {
                        string m_parameterName = (string.IsNullOrWhiteSpace(cp.Alias) ? cp.Name : cp.Alias);
                        string m_evalCode = (string.IsNullOrWhiteSpace(cp.Eval) ? string.Format("$('#{0}').val()", cp.Name) : cp.Eval);

                        if (!string.IsNullOrWhiteSpace(cp.DefaultValue))
                        {
                            sb.AppendFormat("data.{0} = '{1};'\n", m_parameterName, cp.DefaultValue);
                        }
                        else
                        {
                            sb.AppendFormat("data.{0} = {1};\n", m_parameterName, m_evalCode);
                        }
                    }
                }
                sb.AppendLine("  }");

                sb.AppendLine("}");

                retValue = sb.ToString();
            }

            return retValue;
        }

        private string DefineDataTablesColumns()
        {
            string retValue = string.Empty;

            if (this.ColumnsConfig.Columns.Count() > 0)
            {
                StringBuilder sb = new StringBuilder();

                if ((this.FeaturesConfig != null) && (this.FeaturesConfig.Features != null) && (this.FeaturesConfig.Features.Count() > 0))
                {
                    sb.AppendLine(",\"columns\": [");
                }
                else
                {
                    sb.AppendLine("\"columns\": [");
                }

                if (this.SelectionMode == SelectionModes.Multi)
                {
                    Column m_chekcBoxColumn = this.ColumnsConfig.Columns.Single(x => x.Name == this.ColumnsConfig.Key);

                    if (m_chekcBoxColumn != null)
                    {
                        sb.AppendFormat("{{ \"data\": \"{0}\", \"type\": \"{1}\" }},\n", m_chekcBoxColumn.Name, m_chekcBoxColumn.Type.ToString().ToLower());
                    }
                }

                foreach (Column c in this.ColumnsConfig.Columns)
                {
                    switch (c.Type)
                    {
                        case ColumnTypes.Boolean:
                            {
                                sb.AppendLine("{ ");
                                sb.AppendFormat("\"data\": \"{0}\",\n", c.Name);
                                sb.AppendLine("  render: function ( data, type, row ) {");
                                sb.AppendLine("    if ( type === 'display' ) {");
                                sb.AppendLine("      if(data) {");
                                sb.AppendFormat("      return '<input type=\"checkbox\" class=\"css_{0}\" {1} checked>';\n", c.Name, (((BooleanColumn)c).Editable ? "" : "disabled=\"disabled\""));
                                sb.AppendLine("      } else {");
                                sb.AppendFormat("      return '<input type=\"checkbox\" class=\"css_{0}\" {1}>';\n", c.Name, (((BooleanColumn)c).Editable ? "" : "disabled=\"disabled\""));
                                sb.AppendLine("      }");
                                sb.AppendLine("    }");
                                sb.AppendLine("    return data;");
                                sb.AppendLine("  }");
                                sb.AppendLine("},");
                            }
                            break;
                        case ColumnTypes.Image:
                            {
                                sb.AppendLine(c.ToString());
                            }
                            break;
                        case ColumnTypes.Action:
                            {
                                List<ActionDetail> m_details = ((ActionColumn)c).Actions;
                                if (m_details != null && m_details.Count() > 0)
                                {
                                    StringBuilder m_acb = new StringBuilder();
                                    m_acb.Append("{ \"data\": null, \n");    //\"defaultContent\":\"
                                    m_acb.AppendLine("\"orderable\": false,");
                                    m_acb.Append("\"render\": function ( data, type, row ) {\n");
                                    m_acb.Append("  return \"");
                                    foreach (ActionDetail ac in m_details)
                                    {
                                        m_acb.Append(string.Format("{0} ", ac.Render(this.ColumnsConfig.Key)));
                                    }
                                    m_acb.AppendLine("\"}");
                                    m_acb.AppendLine(" }");

                                    sb.AppendLine(m_acb.ToString());
                                }

                            }
                            break;
                        default:
                            {
                                string m_default = string.Empty;
                                if (c.AllowNull)
                                {
                                    m_default = ", \"defaultContent\": \"\"";
                                    if (!string.IsNullOrWhiteSpace(c.DefaultContent))
                                    {
                                        m_default = (!string.IsNullOrWhiteSpace(c.DefaultContent) ? ", \"defaultContent\": \"" + c.DefaultContent + "\"" : "");
                                    }
                                }

                                sb.AppendFormat("{{ \"data\": \"{0}\", \"type\": \"{1}\"{2}{3}{4}{5}}},\n",
                                    c.Name,
                                    (c.Type.ToString() == null ? ColumnTypes.String.ToString().ToLower() : c.Type.ToString().ToLower()),
                                    (c.Type == ColumnTypes.Date ? ", \"dateFormat\":\"dd/mm/yyyyy\"" : ""),
                                    (!c.Visible ? ", \"visible\": false" : ""),
                                    (!string.IsNullOrWhiteSpace(c.Width) ? ", \"width\": \"" + c.Width + "\"" : ""),
                                     m_default);
                            }
                            break;
                    }

                    /*
                    if (c.Type == ColumnTypes.Boolean)
                    {
                        sb.AppendLine("{ ");
                        sb.AppendFormat("\"data\": \"{0}\",\n", c.Name);
                        sb.AppendLine("  render: function ( data, type, row ) {");
                        sb.AppendLine("    if ( type === 'display' ) {");
                        sb.AppendFormat("      return '<input type=\"checkbox\" class=\"css_{0}\" {1}>';\n", c.Name, (((BooleanColumn) c).Editable ? "" : "disabled=\"disabled\""));
                        sb.AppendLine("    }");
                        sb.AppendLine("    return data;");
                        sb.AppendLine("  }");
                        sb.AppendLine("},");
                    }
                    else
                    {
                        sb.AppendFormat("{{ \"data\": \"{0}\", \"type\": \"{1}\"{2}{3}{4} }},\n",
                            c.Name,
                            (c.Type.ToString() == null ? ColumnTypes.String.ToString().ToLower() : c.Type.ToString().ToLower()),
                            (c.Type == ColumnTypes.Date ? ", \"dateFormat\":\"dd/mm/yyyyy\"" : ""),
                            (!c.Visible ? ", \"visible\": false" : ""),
                            (!string.IsNullOrWhiteSpace(c.Width) ? ", \"width\": \"" + c.Width + "\"": ""));
                    }
                    */
                }
                sb.AppendLine("]");

                retValue = sb.ToString();
            }

            return retValue;
        }

        private string DefineDataTablesSearches__()
        {
            string retValue = string.Empty;

            StringBuilder sb = new StringBuilder();

            Searching m_searchingFeature = (Searching)FeaturesConfig.Features.SingleOrDefault(x => x.GetType() == typeof(Searching));
            if (m_searchingFeature != null)
            {
                //m_individualSearch = false;
                m_individualSearch = ((m_searchingFeature.Value == SearchTypes.Individual || m_searchingFeature.Value == SearchTypes.None) ? true : false);

                if ((m_searchingFeature.Value == SearchTypes.Individual) || (m_searchingFeature.Value == SearchTypes.Both))
                {
                    sb.AppendFormat("yadcf.init(m_table{0}, [\n", this.ID);

                    int index = (this.SelectionMode == SelectionModes.Multi ? 1 : 0);
                    foreach (Column c in this.ColumnsConfig.Columns)
                    {
                        ColumnFilter m_filter = m_searchingFeature.Filters.SingleOrDefault(x => x.ColumnName.Equals(c.Name, StringComparison.InvariantCultureIgnoreCase));

                        if (c.Visible)
                        {
                            if (m_filter != null)
                            {
                                switch (m_filter.Type)
                                {
                                    case FilterTypes.Text:
                                        {
                                            sb.AppendFormat("{{ column_number: {0}, filter_type: \"{1}\"{2} }},\n",
                                                index, m_filter.Type.GetDescription().ToString().ToLower(),
                                                (m_searchingFeature.ExternalFilters ? string.Format(", filter_container_id: 'efc_{0}_{1}'", this.ID, index) : ""));
                                        }
                                        break;
                                    case FilterTypes.Date:
                                    case FilterTypes.DateRange:
                                        {
                                            DateColumnFilter m_f = (DateColumnFilter)m_filter;
                                            sb.AppendFormat("{{ column_number: {0}, filter_type: \"{1}\", date_format: '{2}' {3} }},\n",
                                                index,
                                                m_f.Type.GetDescription().ToLower(),
                                                m_f.DateFormat,
                                                (m_searchingFeature.ExternalFilters ? string.Format(", filter_container_id: 'efc_{0}_{1}'", this.ID, index) : ""));
                                        }
                                        break;
                                    case FilterTypes.NumberRange:
                                        {
                                            sb.AppendFormat("{{ column_number: {0}, filter_type: \"{1}\" {2} }},\n",
                                                index, m_filter.Type.GetDescription().ToString().ToLower(),
                                                (m_searchingFeature.ExternalFilters ? string.Format(", filter_container_id: 'efc_{0}_{1}'", this.ID, index) : ""));
                                        }
                                        break;
                                    case FilterTypes.NumberRangeSlider:
                                        {
                                            sb.AppendFormat("{{ column_number: {0}, filter_type: \"{1}\" {2} }},\n",
                                                index, m_filter.Type.GetDescription().ToString().ToLower(),
                                                (m_searchingFeature.ExternalFilters ? string.Format(", filter_container_id: 'efc_{0}_{1}'", this.ID, index) : ""));
                                        }
                                        break;
                                    case FilterTypes.Select:
                                        {
                                            SelectColumnFilter m_selectColumn = (SelectColumnFilter)m_filter;
                                            string m_select2Options = m_selectColumn.ComposeOptions();

                                            sb.AppendFormat("{{ column_number: {0}, select_type: \"{2}\"{3} {4} }},\n",
                                                               index,
                                                               m_filter.Type.GetDescription().ToString().ToLower(),
                                                               m_selectColumn.SelectType.GetDescription().ToString(),
                                                               (m_searchingFeature.ExternalFilters ? string.Format(", filter_container_id: 'efc_{0}_{1}'", this.ID, index) : ""),
                                                               m_select2Options
                                                               );
                                            //filter_type: \"{1}\" (!string.IsNullOrWhiteSpace(m_selectColumn.CustomFunction) ? string.Format(", custom_func: {0}", m_selectColumn.CustomFunction) : ""));
                                        }
                                        break;
                                    case FilterTypes.MultiSelect:
                                        {
                                            MultiSelectColumnFilter m_multiSelectColumn = (MultiSelectColumnFilter)m_filter;
                                            sb.AppendFormat("{{ column_number: {0}, filter_type: \"{1}\", select_type: \"{2}\" {3} }},\n",
                                                               index,
                                                               m_filter.Type.GetDescription().ToString().ToLower(),
                                                               m_multiSelectColumn.SelectType.GetDescription().ToString(),
                                                               (m_searchingFeature.ExternalFilters ? string.Format(", filter_container_id: 'efc_{0}_{1}'", this.ID, index) : ""));
                                        }
                                        break;
                                    case FilterTypes.AutoComplete:
                                        {
                                            sb.AppendFormat("{{ column_number: {0}, filter_type: \"{1}\" {2} }},\n",
                                                index, m_filter.Type.GetDescription().ToString().ToLower(),
                                                (m_searchingFeature.ExternalFilters ? string.Format(", filter_container_id: 'efc_{0}_{1}'", this.ID, index) : ""));
                                        }
                                        break;
                                    case FilterTypes.CustomFunc:
                                        {
                                            CustomFuncColumnFilter m_cfColumn = (CustomFuncColumnFilter)m_filter;
                                            sb.AppendFormat("{{ column_number: {0}, filter_type: \"{1}\", {2} {3} }},\n",
                                                               index,
                                                               m_filter.Type.GetDescription().ToString().ToLower(),
                                                               (!string.IsNullOrWhiteSpace(m_cfColumn.CustomFunction) ? string.Format("custom_func: {0}", m_cfColumn.CustomFunction) : ""),
                                                               (m_searchingFeature.ExternalFilters ? string.Format(", filter_container_id: 'efc_{0}_{1}'", this.ID, index) : ""));
                                        }
                                        break;
                                    case FilterTypes.MultiSelectCustomFunc:
                                        {
                                            MultiSelectColumnFilter m_multiSelectColumn = (MultiSelectColumnFilter)m_filter;
                                            sb.AppendFormat("{{ column_number: {0}, filter_type: \"{1}\", select_type: \"{2}\" {3} {4} }},\n",
                                                               index,
                                                               m_filter.Type.GetDescription().ToString().ToLower(),
                                                               m_multiSelectColumn.SelectType.GetDescription().ToString(),
                                                               (!string.IsNullOrWhiteSpace(m_multiSelectColumn.CustomFunction) ? string.Format(", custom_func: {0}", m_multiSelectColumn.CustomFunction) : ""),
                                                               (m_searchingFeature.ExternalFilters ? string.Format(", filter_container_id: 'efc_{0}_{1}'", this.ID, index) : ""));
                                        }
                                        break;
                                    default:
                                        break;
                                }

                                #region DA CANCELLARE ?
                                //if ((m_filter.Type == FilterTypes.Date) || (m_filter.Type == FilterTypes.DateRange))
                                //{
                                //    if (m_searchingFeature.ExternalFilters)
                                //    {
                                //        sb.AppendFormat("{{ column_number: {0}, filter_type: \"{1}\", date_format: '{2}', filter_container_id: 'efc_{3}_{0}' }},\n", index, m_filter.Type.GetDescription().ToLower(), m_filter.DateFormat, this.ID);
                                //    }
                                //    else
                                //    {
                                //        sb.AppendFormat("{{ column_number: {0}, filter_type: \"{1}\", date_format: '{2}' }},\n", index, m_filter.Type.GetDescription().ToLower(), m_filter.DateFormat);
                                //    }
                                //}
                                //else
                                //{
                                //    if (m_searchingFeature.ExternalFilters)
                                //    {
                                //        sb.AppendFormat("{{ column_number: {0}, filter_type: \"{1}\",  select_type: \"select2\", filter_container_id: 'efc_{2}_{0}' }},\n", index, m_filter.Type.GetDescription().ToString().ToLower(), this.ID);
                                //    }
                                //    else
                                //    {
                                //        sb.AppendFormat("{{ column_number: {0}, filter_type: \"{1}\" }},\n", index, m_filter.Type.GetDescription().ToString().ToLower());
                                //    }
                                //}
                                #endregion

                                index++;
                            }
                        }
                        else
                        {
                            index++;
                        }
                    }

                    if (m_searchingFeature.ExternalFilters)
                    {
                        sb.Append("], { externally_triggered: true });\n");
                        //sb.AppendFormat("], { externally_triggered: resizeGrid({0}) });\n", this.ID);
                    }
                    else
                    {
                        sb.Append("]);\n");
                    }
                }
            }

            retValue = sb.ToString();

            return retValue;
        }

        private string DefineDataTablesSearches()
        {
            string retValue = string.Empty;

            StringBuilder sb = new StringBuilder();

            Searching m_searchingFeature = (Searching)FeaturesConfig.Features.SingleOrDefault(x => x.GetType() == typeof(Searching));
            if (m_searchingFeature != null)
            {
                //m_individualSearch = false;
                m_individualSearch = ((m_searchingFeature.Value == SearchTypes.Individual || m_searchingFeature.Value == SearchTypes.None) ? true : false);

                if ((m_searchingFeature.Value == SearchTypes.Individual) || (m_searchingFeature.Value == SearchTypes.Both))
                {
                    sb.AppendFormat("yadcf.init(m_table{0}, [\n", this.ID);

                    int index = (this.SelectionMode == SelectionModes.Multi ? 1 : 0);
                    int m_multiOrSingle = (this.SelectionMode == SelectionModes.Multi ? 1 : 0);
                    foreach (ColumnFilter c in m_searchingFeature.Filters)
                    {
                        int m_theColumnIndex = this.ColumnsConfig.Columns.FindIndex(x => x.Name == c.ColumnName);

                        m_theColumnIndex = m_theColumnIndex + m_multiOrSingle;

                        switch (c.Type)
                        {
                            case FilterTypes.CustomChoice:
                                {
                                    sb.AppendFormat("{{ column_number: {0}, data: [{1}], filter_default_label: \"{2}\"{3} }},\n",
                                       m_theColumnIndex,
                                       ((CustomChoiceFilter)c).BuildData(),
                                       ((CustomChoiceFilter)c).FilterDefaultLabel,
                                       (m_searchingFeature.ExternalFilters ? string.Format(", filter_container_id: 'efc_{0}_{1}'", this.ID, index) : ""));

                                    index++;
                                }
                                break;
                            case FilterTypes.Text:
                                {
                                    sb.AppendFormat("{{ column_number: {0}, filter_type: \"{1}\"{2} }},\n",
                                        m_theColumnIndex, c.Type.GetDescription().ToString().ToLower(),
                                        (m_searchingFeature.ExternalFilters ? string.Format(", filter_container_id: 'efc_{0}_{1}'", this.ID, index) : ""));

                                    index++;
                                }
                                break;
                            case FilterTypes.Date:
                            case FilterTypes.DateRange:
                                {
                                    DateColumnFilter m_f = (DateColumnFilter)c;
                                    sb.AppendFormat("{{ column_number: {0}, filter_type: \"{1}\", date_format: '{2}' {3} }},\n",
                                        m_theColumnIndex,
                                        m_f.Type.GetDescription().ToLower(),
                                        m_f.DateFormat,
                                        (m_searchingFeature.ExternalFilters ? string.Format(", filter_container_id: 'efc_{0}_{1}'", this.ID, index) : ""));

                                    index++;
                                }
                                break;
                            case FilterTypes.NumberRange:
                                {
                                    sb.AppendFormat("{{ column_number: {0}, filter_type: \"{1}\" {2} }},\n",
                                        m_theColumnIndex, c.Type.GetDescription().ToString().ToLower(),
                                        (m_searchingFeature.ExternalFilters ? string.Format(", filter_container_id: 'efc_{0}_{1}'", this.ID, index) : ""));

                                    index++;
                                }
                                break;
                            case FilterTypes.NumberRangeSlider:
                                {
                                    sb.AppendFormat("{{ column_number: {0}, filter_type: \"{1}\" {2} }},\n",
                                        m_theColumnIndex, c.Type.GetDescription().ToString().ToLower(),
                                        (m_searchingFeature.ExternalFilters ? string.Format(", filter_container_id: 'efc_{0}_{1}'", this.ID, index) : ""));

                                    index++;
                                }
                                break;
                            case FilterTypes.Select:
                                {
                                    SelectColumnFilter m_selectColumn = (SelectColumnFilter)c;
                                    string m_select2Options = m_selectColumn.ComposeOptions();

                                    sb.AppendFormat("{{ column_number: {0}, select_type: \"{2}\"{3} {4} }},\n",
                                                       m_theColumnIndex,
                                                       c.Type.GetDescription().ToString().ToLower(),
                                                       m_selectColumn.SelectType.GetDescription().ToString(),
                                                       (m_searchingFeature.ExternalFilters ? string.Format(", filter_container_id: 'efc_{0}_{1}'", this.ID, index) : ""),
                                                       m_select2Options
                                                       );

                                    index++;
                                }
                                break;
                            case FilterTypes.MultiSelect:
                                {
                                    MultiSelectColumnFilter m_multiSelectColumn = (MultiSelectColumnFilter)c;
                                    sb.AppendFormat("{{ column_number: {0}, filter_type: \"{1}\", select_type: \"{2}\" {3} }},\n",
                                                       m_theColumnIndex,
                                                       c.Type.GetDescription().ToString().ToLower(),
                                                       m_multiSelectColumn.SelectType.GetDescription().ToString(),
                                                       (m_searchingFeature.ExternalFilters ? string.Format(", filter_container_id: 'efc_{0}_{1}'", this.ID, index) : ""));

                                    index++;
                                }
                                break;
                            case FilterTypes.AutoComplete:
                                {
                                    sb.AppendFormat("{{ column_number: {0}, filter_type: \"{1}\" {2} }},\n",
                                        m_theColumnIndex, c.Type.GetDescription().ToString().ToLower(),
                                        (m_searchingFeature.ExternalFilters ? string.Format(", filter_container_id: 'efc_{0}_{1}'", this.ID, index) : ""));

                                    index++;
                                }
                                break;
                            case FilterTypes.CustomFunc:
                                {
                                    CustomFuncColumnFilter m_cfColumn = (CustomFuncColumnFilter)c;
                                    sb.AppendFormat("{{ column_number: {0}, filter_type: \"{1}\", {2} {3} }},\n",
                                                       m_theColumnIndex,
                                                       c.Type.GetDescription().ToString().ToLower(),
                                                       (!string.IsNullOrWhiteSpace(m_cfColumn.CustomFunction) ? string.Format("custom_func: {0}", m_cfColumn.CustomFunction) : ""),
                                                       (m_searchingFeature.ExternalFilters ? string.Format(", filter_container_id: 'efc_{0}_{1}'", this.ID, index) : ""));

                                    index++;
                                }
                                break;
                            case FilterTypes.MultiSelectCustomFunc:
                                {
                                    MultiSelectColumnFilter m_multiSelectColumn = (MultiSelectColumnFilter)c;
                                    sb.AppendFormat("{{ column_number: {0}, filter_type: \"{1}\", select_type: \"{2}\" {3} {4} }},\n",
                                                       m_theColumnIndex,
                                                       c.Type.GetDescription().ToString().ToLower(),
                                                       m_multiSelectColumn.SelectType.GetDescription().ToString(),
                                                       (!string.IsNullOrWhiteSpace(m_multiSelectColumn.CustomFunction) ? string.Format(", custom_func: {0}", m_multiSelectColumn.CustomFunction) : ""),
                                                       (m_searchingFeature.ExternalFilters ? string.Format(", filter_container_id: 'efc_{0}_{1}'", this.ID, index) : ""));

                                    index++;
                                }
                                break;
                            default:
                                break;
                        }
                    }

                    if (m_searchingFeature.ExternalFilters)
                    {
                        sb.Append("], { externally_triggered: true });\n");
                    }
                    else
                    {
                        sb.Append("]);\n");
                    }
                }
            }

            retValue = sb.ToString();

            return retValue;
        }

        private string[] DefineDataTablesSelectionMode()
        {
            string[] retValue = new string[2] { string.Empty, string.Empty };

            string m_cssSelectedRow = (!string.IsNullOrEmpty(this.BootstrapClasses) ? "active" : "selected");

            if (this.SelectionMode == SelectionModes.Multi)
            {
                StringBuilder sb = new StringBuilder();

                if ((this.FeaturesConfig != null) && (this.FeaturesConfig.Features != null) && (this.FeaturesConfig.Features.Count() > 0))
                {
                    sb.AppendLine(",\"columnDefs\": [{");
                }
                else
                {
                    sb.AppendLine("\"columnDefs\": [{");
                }

                sb.AppendLine("   'targets': 0,");
                sb.AppendLine("   'searchable': false,");
                sb.AppendLine("   'orderable': false,");
                sb.AppendLine("   'className': 'dt-body-center',");
                sb.AppendLine("   'render': function (data, type, full, meta) {");
                sb.AppendLine("       return '<input type=\"checkbox\" class=\"multiRowSel\">';");
                sb.AppendLine("   },");
                sb.AppendLine("}],");

                sb.AppendLine("\"rowCallback\": function (row, data, dataIndex) {");
                sb.AppendFormat("    if (IsInArray(rows_selected_{0}, data, '{1}') !== -1) {{", this.ID, this.ColumnsConfig.Key);
                //sb.AppendLine("        $(row).find('input[type=\"checkbox\"]').prop('checked', true);");
                sb.AppendLine("        $(row).find('checkbox.multiRowSel').prop('checked', true);");
                sb.AppendFormat("        $(row).addClass('{0}');\n", m_cssSelectedRow);
                sb.AppendLine("      }");
                sb.AppendLine("}");

                retValue[0] = sb.ToString();
                retValue[1] = string.Format("HandleSelectionByCheckboxes('table{0}', m_table{0}, rows_selected_{0}, '{1}', '{2}');\n\n", this.ID, this.ColumnsConfig.Key, m_cssSelectedRow);
            }

            if (this.SelectionMode == SelectionModes.Single)
            {
                StringBuilder sb = new StringBuilder();

                sb.AppendFormat("$('#table{0} tbody').on( 'click', 'tr', function () {{\n", this.ID);
                sb.AppendFormat("   if ( $(this).hasClass('{0}') ) {{\n", m_cssSelectedRow);
                sb.AppendFormat("     $(this).removeClass('{0}');\n", m_cssSelectedRow);
                sb.AppendLine("   }");
                sb.AppendLine("   else {");
                sb.AppendFormat("      m_table{0}.$('tr.{1}').removeClass('{1}');\n", this.ID, m_cssSelectedRow);
                sb.AppendFormat("        $(this).addClass('{0}');\n", m_cssSelectedRow);
                sb.AppendLine("   }");
                sb.AppendLine("  });");

                retValue[1] = sb.ToString();
            }

            if ((this.FeaturesConfig != null) && (this.FeaturesConfig.Features != null) && (this.FeaturesConfig.Features.Count() > 0))
            {
                for (int i = 0; i < this.FeaturesConfig.Features.Count(); i++)
                {
                    if (this.FeaturesConfig.Features[i].GetType() == typeof(Searching))
                    {
                        if (((Searching)this.FeaturesConfig.Features[i]).Value == SearchTypes.None)
                        {
                            //string m_searchInput = "$(\"input[type=search]\").prop(\"disabled\", true);";
                            string m_searchInput = string.Format("$(\"#table{0}_filter label:contains('Search:')\").text('');\n\n$(\"#table{0}_filter input[type=search]\").hide();", this.ID);

                            retValue[1] += "\n\n" + m_searchInput;
                        }
                    }
                }
            }

            return retValue;
        }

        private string DefineDataTablesToolbar()
        {
            string retValue = string.Empty;

            StringBuilder sb = new StringBuilder();

            sb.AppendFormat("$(\"div.TB_{0}\").html(\"", this.ID);
            if (this.Toolbar != null)
            {
                foreach (IconButton ic in Toolbar)
                {
                    sb.AppendFormat("<i class=\'fa {0}\' style=\'cursor: pointer;\' onclick='{1}()'></i>&nbsp;&nbsp;", ic.Icon, ic.Callback);
                }
            }
            sb.Append("\");");

            retValue = sb.ToString();

            return retValue;
        }

        private string DefineDataTablesButtons()
        {
            string retValue = string.Empty;

            StringBuilder sb = new StringBuilder();

            if ((this.FeaturesConfig != null) && (this.FeaturesConfig.Features != null) && (this.FeaturesConfig.Features.Count() > 0))
            {
                sb.AppendLine(",buttons: [");
            }
            else
            {
                sb.AppendLine("buttons: [");
            }

            if (this.ControllerConfig.LoadingMode == LoadingModes.OnDemand)
            {
                string m_cbName = string.Format("javascript:RedrawGrid(m_table{0})", this.ID);

                if (this.ControllerConfig.Validation == null)
                {
                    sb.AppendLine("{");
                    sb.AppendLine("  text: 'Carica',");
                    sb.AppendLine("  className: 'sButtonCarica',");
                    sb.AppendLine("  action: function (e, dt, node, config) {");
                    sb.AppendFormat("    {0};", m_cbName);
                    sb.AppendLine("  }");
                    sb.AppendLine("},");
                }
                else
                {
                    if ((this.ControllerConfig.Validation.ValidationParameters != null) && (this.ControllerConfig.Validation.ValidationParameters.Count() > 0))
                    {
                        sb.AppendLine("{");
                        sb.AppendLine("  text: 'Carica',");
                        sb.AppendLine("  className: 'sButtonCarica',");
                        sb.AppendLine("  action: function (e, dt, node, config) {");

                        sb.AppendLine("     var arCtrls = [];");
                        foreach (ValidationParameter vp in this.ControllerConfig.Validation.ValidationParameters)
                        {
                            sb.AppendFormat("     arCtrls.push('{0}');\n", vp.Name);
                        }

                        sb.AppendLine("          var res = ValidateTableParameters(arCtrls);");
                        sb.AppendFormat("      if(res) {{ {0}; }} else {{ alert('{1}'); }} \n", m_cbName, this.ControllerConfig.Validation.Message);

                        sb.AppendLine("  }");
                        sb.AppendLine("},");
                    }
                    else
                    {
                        sb.AppendLine("{");
                        sb.AppendLine("  text: 'Carica',");
                        sb.AppendLine("  className: 'sButtonCarica',");
                        sb.AppendLine("  action: function (e, dt, node, config) {");
                        sb.AppendFormat("     var elements = $('#{0}').prop('elements');\n", this.ControllerConfig.Validation.FormId);

                        sb.AppendLine("       if(elements != undefined) { ");
                        sb.AppendLine("           var index1 = 0; ");
                        sb.AppendLine("           $.each(elements, function(i,o){");
                        sb.AppendLine("              if($(o).prop('id') !== '') { ");
                        sb.AppendLine("                     index1++; ");
                        sb.AppendLine("              } ");
                        sb.AppendLine("           }); ");

                        //sb.AppendLine("       var index1 = elements.length; ");
                        sb.AppendLine("           var index2 = 0; ");
                        sb.AppendLine("           $.each(elements, function(i,o){");
                        sb.AppendLine("              if($(o).hasClass('ng-valid')) { ");
                        sb.AppendLine("                     index2++; ");
                        sb.AppendLine("              } ");
                        sb.AppendLine("           }); ");
                        sb.AppendFormat("         if(index1 != index2) {{ alert('{0}'); }} else {{ {1} }}\n", this.ControllerConfig.Validation.Message, m_cbName);
                        sb.AppendFormat("     }} else {{ {0}; }}\n", m_cbName);
                        sb.AppendLine("  }");
                        sb.AppendLine("},");
                    }
                }
            }

            if (this.SelectionMode == SelectionModes.Multi)
            {
                sb.AppendLine("{");
                sb.AppendLine("  text: 'Mostra Selezione',");
                sb.AppendLine("  className: 'sMostra_Selezione',");
                sb.AppendLine("  action: function (e, dt, node, config) {");
                sb.AppendFormat("    if(rows_selected_{0}.length > 0) {{", this.ID);
                sb.AppendFormat("      ArrayToTable('selItemsTable', rows_selected_{0});", this.ID);
                sb.AppendLine("        $(\"#selectedItemsDialog\").dialog({ width: \"auto\" });");
                sb.AppendLine("      } else { alert(\"Nessun elemento selezionato.\"); }");
                sb.AppendLine("  }");
                sb.AppendLine("},");
            }

            if ((Buttons != null) && (Buttons.Count() > 0))
            {
                string m_callback = string.Empty;

                foreach (ButtonBase b in this.Buttons)
                {
                    if (b.GetType() == typeof(UtilityButton))
                    {
                        //sb.AppendFormat(" '{0}' ", ((UtilityButton)b).GetCode());

                        sb.AppendLine("{");
                        sb.AppendFormat("  extend: '{0}', text: '{1}', title: '{2}' ", ((UtilityButton)b).GetCode(), b.Text, ((UtilityButton)b).Title);
                        sb.AppendLine("},");
                    }
                    else
                    {
                        if (b.GetType() == typeof(CustomButton)) m_callback = ((CustomButton)b).Callback;
                        if (b.GetType() == typeof(CrudAddButton)) m_callback = ((CrudAddButton)b).Callback;
                        if (b.GetType() == typeof(CrudDeleteButton)) m_callback = ((CrudDeleteButton)b).Callback;
                        if (b.GetType() == typeof(CrudEditButton)) m_callback = ((CrudEditButton)b).Callback;
                        if (b.GetType() == typeof(CrudLoadButton)) m_callback = ((CrudLoadButton)b).Callback;

                        sb.AppendLine("{");
                        sb.AppendFormat("  text: '{0}',", b.Text);
                        sb.AppendFormat("  className: 's{0}',", b.Text.Replace(' ', '_'));
                        sb.AppendLine("  action: function (e, dt, node, config) {");

                        if ((b.Parameters != null) && (b.Parameters.Count() > 0))
                        {
                            string m_parameters = string.Empty;
                            foreach (ButtonCallbackParameter bcp in b.Parameters)
                            {
                                m_parameters += bcp.Value + ",";
                            }

                            sb.AppendFormat("     {0}({1});", m_callback, m_parameters.RemoveLast());
                        }
                        else
                        {
                            sb.AppendFormat("     {0}();", m_callback);
                        }

                        sb.AppendLine("  }");
                        sb.AppendLine("},");
                    }
                }
            }

            sb.AppendLine("]");

            retValue = sb.ToString();

            return retValue;
        }

        private string DefineTablePartsSequence()
        {
            LengthChange m_lengthChangeFeature = (LengthChange)FeaturesConfig.Features.SingleOrDefault(x => x.GetType() == typeof(LengthChange));

            string m_toolbar = string.Format("<\"TB_{0}\">", this.ID);

            string retValue = string.Format(",dom: '{2}B{1}{0}rtip',",
                (m_lengthChangeFeature.Value ? "l" : ""),
                (m_individualSearch ? "" : "f"),
                (this.Toolbar != null ? m_toolbar : string.Empty));

            return retValue;
        }

        private string DefineTableCallbacks()
        {
            string retValue = string.Empty;

            if (this.EventsConfig != null && this.EventsConfig.Events.Any(x => x.Type == InternalTypes.Callback))
            {
                StringBuilder sb = new StringBuilder();

                foreach (EventBase m_event in this.EventsConfig.Events.Where(x => x.Type == InternalTypes.Callback))
                {
                    sb.AppendFormat(",\"{0}\": function ( {1} ) {{ if(!CheckUndefined({2})) {{ {2}( row, data, index ); }} }}\n", m_event.Name, m_event.FunctionSignature, m_event.Callback);
                }

                retValue = sb.ToString();
            }

            return retValue;
        }

        private string DefineTableEvents()
        {
            string retValue = string.Empty;

            if (this.EventsConfig != null && this.EventsConfig.Events.Any(x => x.Type == InternalTypes.Event))
            {
                StringBuilder sb = new StringBuilder();

                sb.AppendFormat("m_table{0}\n", this.ID);

                int m_index = 0;
                int m_max = this.EventsConfig.Events.Where(x => x.Type == InternalTypes.Event).Count();
                foreach (EventBase m_event in this.EventsConfig.Events.Where(x => x.Type == InternalTypes.Event))
                {
                    sb.AppendFormat(".on('{0}.dt', function ( {1} ) {{ if(!CheckUndefined({2})) {{ {2}( {1} ); }} }} )", m_event.Name, m_event.FunctionSignature, m_event.Callback);

                    if (m_index < m_max)
                    {
                        sb.Append("\n");
                        m_index++;
                    }
                    else
                    {
                        sb.Append(";");
                    }
                }

                retValue = sb.ToString();
            }

            return retValue;
        }

        private string DefineEditableColumns()
        {
            string retValue = string.Empty;

            if (this.ColumnsConfig.Editable != null)
            {
                StringBuilder sb = new StringBuilder();

                string m_eColumns = string.Empty;
                string m_nColumns = string.Empty;

                if (this.ColumnsConfig.Editable != null)
                {
                    int index = 0;
                    int[] m_editableColumns = new int[this.ColumnsConfig.Columns.Count];
                    int[] m_nullableColumns = new int[this.ColumnsConfig.Columns.Count];

                    // define columns property...
                    foreach (Column c in this.ColumnsConfig.Columns)
                    {
                        if (c.Editable) m_editableColumns[index] = index;
                        else m_editableColumns[index] = -1;

                        if (c.AllowNull) m_nullableColumns[index] = index;
                        else m_nullableColumns[index] = -1;

                        index++;
                    }

                    m_eColumns = string.Join(",", m_editableColumns.Where(x => x != -1));
                    m_nColumns = string.Join(",", m_nullableColumns.Where(x => x != -1));
                }

                sb.AppendFormat("m_table{0}.MakeCellsEditable({{\n", this.ID);
                sb.AppendFormat("   'onUpdate': {0},\n", (!string.IsNullOrWhiteSpace(this.ColumnsConfig.Editable.Callback) ? this.ColumnsConfig.Editable.Callback : "function(){}"));
                sb.AppendFormat("   'inputCss': '{0}',\n", (!string.IsNullOrWhiteSpace(this.ColumnsConfig.Editable.InputCss) ? this.ColumnsConfig.Editable.InputCss : ""));
                sb.AppendFormat("   'columns': [{0}],\n", m_eColumns);
                sb.AppendLine("   'allowNulls': {");
                sb.AppendFormat("     'columns': [{0}],\n", m_nColumns);
                sb.AppendFormat("     'errorClass': '{0}'\n", (!string.IsNullOrWhiteSpace(this.ColumnsConfig.Editable.ErrorClass) ? this.ColumnsConfig.Editable.ErrorClass : ""));
                sb.AppendLine("   },");
                sb.AppendLine("   'confirmationButton': {");
                sb.AppendFormat("     'confirmCss': '{0}',\n", (!string.IsNullOrWhiteSpace(this.ColumnsConfig.Editable.ConfirmCss) ? this.ColumnsConfig.Editable.ConfirmCss : ""));
                sb.AppendFormat("     'cancelCss': '{0}'\n", (!string.IsNullOrWhiteSpace(this.ColumnsConfig.Editable.CancelCss) ? this.ColumnsConfig.Editable.CancelCss : ""));
                sb.AppendLine("   }");
                sb.AppendLine("});");

                //
                retValue = sb.ToString();
            }

            return retValue;
        }

        private string ExtractSelector(string content)
        {
            string retValue = string.Empty;

            int pos = content.IndexOf("type=", StringComparison.InvariantCultureIgnoreCase);
            int space = content.IndexOf(" ", pos);
            string m_type = content.Substring(pos + 5, (space - (pos + 5))).Replace("'", "");

            pos = content.IndexOf("class=", StringComparison.InvariantCultureIgnoreCase);
            space = content.IndexOf(" ", pos);
            string m_class = content.Substring(pos + 6, (space - (pos + 6))).Replace("'", "");

            retValue = string.Format("{0}.{1}", m_type, m_class);

            return retValue;
        }
    }
}
